# coding: utf8
from time import time
import urlparse
import time
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
from PyQt4.QtNetwork import *
def toString(s):
    #if HAS_PYSIDE:
    #    if isinstance(s, basestring):
    #        return s
    if isinstance(s, QString):
    return u"%s" % s
    return s.toString()

class HookUrl(object):
	def __init__(self,cookie):	
		self.hookUrls = list()
		self.cookie = cookie
		self.timeCount = 1
	def report(self,request,data):
		if self.cookie is not None:
			try:
				request.setRawHeader("Cookie",self.cookie)
			except Exception as e:
				print "[-] Set Cookie wrong!",str(e)
		postdata =""
		tmp={}
		print "[+] Hook Url:",request.url()
#		print "[+] Hook Host:",request.url().host()
		if data is not None:
			postdata= data.readAll()
			#print "[+] Data:",data.readAll()
		try:
			url = unicode(toString(request.url()))
		except Exception as e:
			print "[-] Exception :",str(e)
#		print "[+] Get request:",url
		tmp['url'] = url
		tmp['post'] =postdata
		tmp['host'] = urlparse.urlparse(url)[1]
		tmp['tag'] ="" 
		tmp['referer'] ="" 
		self.hookUrls.append(tmp)
		self.timeCount=1
	def getTimeCount(self):
		return self.timeCount
	def setTimeCount(self,timeCount):
		self.timeCount = timeCount
	def getHookUrls(self):
		return self.hookUrls
	def cleanHookUrls(self):
		self.hookUrls= list()
class MyAccessManager(QNetworkAccessManager):
    def createRequest(manager, operation, request, data):
        if manager.requestHook!=None:
            manager.requestHook.report(request,data)
        reply = QNetworkAccessManager.createRequest(manager, operation, request, data)
        return reply

    def __init__(self,browser,requestHook,url):
        self.requestHook=requestHook
	super(MyAccessManager,self).__init__()


class MyWebView(QWebView):
    def __init__(self,actionEventHook=None):
        super(MyWebView,self).__init__()
        self.actionEventHook=actionEventHook
        self.installEventFilter(self);
        self.page().installEventFilter(self);
        self.page().mainFrame().installEventFilter(self);

    def _debug(self,string):
        #print string
        pass

    def eventFilter(self,obj,ev):
        #print ev
        if isinstance(ev,QKeyEvent):
            self._debug(str("KeyBoard : ")+str(ev.type())+" | "+str(ev.key())+" | "+str(ev.count())+" | "+str(ev.text())+" | "+str(time.time()))
            if self.actionEventHook!=None:
                self.actionEventHook.report(str("KeyBoard : ")+" | "+str(ev.type())+" | "+str(ev.key())+" | "+str(ev.count())+" | "+str(ev.text())+" | "+str(time.time()))
        elif isinstance(ev,QPaintEvent):
            pass
        elif isinstance(ev,QMouseEvent):
            self._debug(str("Mouse : ")+str(ev.type())+" | "+str(ev.x())+","+str(ev.y())+" | "+str(ev.button())+" | "+str(ev.buttons().__int__())+" | "+str(time.time()))
            if self.actionEventHook!=None:
                self.actionEventHook.report(str("Mouse : ")+" | "+str(ev.type())+" | "+str(ev.x())+","+str(ev.y())+" | "+str(ev.button())+" | "+str(time.time()))
        else:
            if ev.type()==184 or ev.type()==77:
                pass
            else:
                self._debug(str("Other : ")+str(ev.type())+" | "+str(ev)+" | "+str(time.time()))
                pass
                #self.actionEventHook.writeLine(str("Other : ")+str(ev.type())+" | "+str(ev)+" | "+str(time.time()))

        #if isinstance(ev)==
        return False
    
    def mousePressEvent(self,ev):
        self._debug(str("Mouse : ")+str(ev.type())+" | "+str(ev.x())+","+str(ev.y())+" | "+str(ev.button())+" | "+str(ev.buttons().__int__())+" | "+str(time.time()))
        super(MyWebView,self).mousePressEvent(ev)

    def mouseReleaseEvent(self,ev):
        self._debug(str("Mouse : ")+str(ev.type())+" | "+str(ev.x())+","+str(ev.y())+" | "+str(ev.button())+" | "+str(ev.buttons().__int__())+" | "+str(time.time()))
        super(MyWebView,self).mouseReleaseEvent(ev)

    def mouseMoveEvent(self,ev):
        self._debug(str("Mouse : ")+str(ev.type())+" | "+str(ev.x())+","+str(ev.y())+" | "+str(ev.button())+" | "+str(ev.buttons().__int__())+" | "+str(time.time()))
        super(MyWebView,self).mouseMoveEvent(ev)
    
    

class WebKitBrowser():
    '''
    娴忚鍣ㄧ粍浠讹紝鍔犺浇椤甸潰锛岃幏鍙朌OM鏍戯紝鎵цJavaScript锛屾ā鎷熸祻瑙堝櫒鍚勭閿洏榧犳爣浜嬩欢
    '''

    def __init__(self,application=None,Hookers=None,properties=None):
        '''
        鍒濆鍖栨祻瑙堝櫒缁勪欢
        '''
        self.responseNum=0

        self.javascriptAlertHook=None
        self.actionEventHook=None
        self.requestHook=None
        self.isView=False
        self.isImgLoad=False
        self.isPluginLoad=False
        self.isExeJavascript=True
        self.isAuditXss=False
        self.isIgnoreSslError=True
        self.proxyIp=None
        self.proxyPort=None

        if Hookers!=None and Hookers.get("javascriptAlertHook")!=None:
            self.javascriptAlertHook=Hookers.get("javascriptAlertHook")
        if Hookers!=None and Hookers.get("actionEventHook")!=None:
            self.actionEventHook=Hookers.get("actionEventHook")
        if Hookers!=None and Hookers.get("requestHook")!=None:
            self.requestHook=Hookers.get("requestHook")
        if properties!=None and properties.get("isView")!=None:
            self.isView=properties.get("isView")
        if properties!=None and properties.get("isImgLoad")!=None:
            self.isImgLoad=properties.get("isImgLoad")
        if properties!=None and properties.get("isPluginLoad")!=None:
            self.isPluginLoad=properties.get("isPluginLoad")
        if properties!=None and properties.get("isExeJavascript")!=None:
            self.isExeJavascript=properties.get("isExeJavascript")
        if properties!=None and properties.get("isAuditXss")!=None:
            self.isAuditXss=properties.get("isAuditXss")
        if properties!=None and properties.get("isIgnoreSslError")!=None:
            self.isIgnoreSslError=properties.get("isIgnoreSslError")
        if properties!=None and properties.get("proxy")!=None:
            self.proxyIp=properties.get("proxy").get("proxyIp")
            self.proxyPort=properties.get("proxy").get("proxyPort")
        if application==None:
            self.application=QApplication([])
            self.applicationCreate=True
        else:
            self.application=application
            self.applicationCreate=False
        self._initEnv()

    def getWebView(self):
        return self.webView
    def getWebPage(self):
        return self.webPage
    def getWebFrame(self):
        return self.webFrame

    def waitLoad(self, least = 0, most = 10):
        '''
        绛夊緟椤甸潰鍔犺浇瀹屾瘯
        '''
        start = time.time()
        while (self._loadStatus == 'start' and time.time() - start < most) or time.time() - start < least:
            self.waitEvent(0.1)
            #self.application.processEvents()

    def waitEvent(self,timeOut=0.1):
        if timeOut==None or timeOut==0:
            return
        self.application.processEvents()
        time.sleep(timeOut)

    def waitLoop(self,timeOut=0.5):
        '''
        寤舵椂timeOut鏃堕棿
        '''
        if timeOut==None or timeOut==0:
            return
        start=time.time()
        while time.time()-start<timeOut:
            self.waitEvent(timeOut)
            #self.application.processEvents()
        #time.sleep(timeOut)

    def html(self):
        '''
        鑾峰彇宸茬粡琚獼avaScript澶勭悊瀹屾瘯鐨剈tf8 html浠ｇ爜
        '''
        return self.webFrame.toHtml().toUtf8()

    def _initEnv(self):
        '''
        鍒濆鍖朩ebPage,WebView,WebFrame
        '''

        self.webPage = QWebPage()
        #self.webView=QWebView()
        self.webView=MyWebView(self.actionEventHook)
        self.webView.setPage(self.webPage)
        self.webFrame = self.webPage.currentFrame()

        self.webPage.javaScriptAlert = self._alertHook
        self.url=''

        self._loadStatus = 'init'
        self.webPage.connect(self.webPage,SIGNAL('loadFinished(bool)'),self._onLoadFinished)
        self.webPage.connect(self.webPage,SIGNAL('loadStarted()'),self._onLoadStarted)
        self.webPage.unsupportedContent.connect(self._onUnsupportedContent)
        self.webPage.downloadRequested.connect(self._onDownloadRequest)

        self.manager=MyAccessManager(self,self.requestHook,self.url)
        self.webPage.setNetworkAccessManager(self.manager)
        #self.manager=self.webPage.networkAccessManager()
        self.manager.finished.connect(self._onReply)
        self.manager.sslErrors.connect(self._onManagerSslErrors)

        self.webPage.settings().setAttribute(QWebSettings.PluginsEnabled,self.isPluginLoad)
        self.webPage.settings().setAttribute(QWebSettings.AutoLoadImages,self.isImgLoad)
        self.webPage.settings().setAttribute(QWebSettings.JavascriptEnabled,self.isExeJavascript)
        self.webPage.settings().setAttribute(QWebSettings.XSSAuditingEnabled,self.isAuditXss)
        if self.isView==True:
            self.webView.show()
        

    def _onUnsupportedContent(self, reply, outfd=None):
        #print "[-] unsupported"
        if not reply.error():
            return
            self._start_download(reply, outfd)
        else:
            self._debug(ERROR, "Error on unsupported content: %s" % reply.errorString())

    def _onDownloadRequest(self,req):
        pass

    def _startDownload(self,reply,outfd):
        url = unicode(toString(reply.url()))
        path = None
        self._debug(INFO, "Start download: %s" % url)
        '''
        if outfd is None:
            path = self._get_filepath_for_url(url, reply)
            outfd = open(path, "wb")
        '''
        def _on_ready_read():
            data = reply.readAll()
            if getattr(reply, 'downloaded_nbytes', None) is None:
                reply.downloaded_nbytes= 0
            reply.downloaded_nbytes += len(data)
            #outfd.write(data)
            #if data.data().indexOf(self.incTag)>=0:
            #    self._debug('inc vuln')
            self._debug(DEBUG, "Read from download stream (%d bytes): %s"
                % (len(data), url))
        def _on_network_error():
            self._debug(ERROR, "Network error on download: %s" % url)
        def _on_finished():
            data = reply.readAll()
            if len(data):
                if getattr(reply, 'downloaded_nbytes at end', None) is None:
                    reply.downloaded_nbytes= 0
                reply.downloaded_nbytes += len(data)
                #outfd.write(data)
                #if data.data().indexOf(self.incTag)>=0:
                #    self._debug('inc vuln')
        reply.readyRead.connect(_on_ready_read)
        reply.error.connect(_on_network_error)
        reply.finished.connect(_on_finished)
        self._debug(INFO, "Start download: %s" % url)

    def _release(self):
        if self.webPage!=None:
            #print 'del page'
            #del self.webPage
            self.webPage=None
        if self.webFrame!=None:
            #del self.webFrame
            self.webFrame=None
        if self.webView!=None:
            #del self.webView
            self.webView=None

    def close(self):
        '''
        鍏抽棴娴忚鍣ㄧ粍浠�
        '''
        self._release()
        if self.applicationCreate:
            self.application.exit()

    def setHtml(self,url,htmlStr):
        '''
        璁剧疆html
        '''
        self._initEnv()
        self.url=url
        self.webFrame.setHtml(htmlStr)


    def send(self,url,method='GET',cookieDict=None,otherHeaderDict=None,body=None,proxyIp=None,proxyPort=8080):
        '''
        鍔犺浇椤甸潰
        '''
        '''
        self._release()

        self._initEnv()
        '''

        self.url=url
        alarm = time.time()
        if cookieDict!=None:
            self._updateCookie(url,urlparse.urlparse(url)[1],'/',cookieDict)

        if proxyIp!=None:
            proxy=QNetworkProxy()
            proxy.setType(QNetworkProxy.HttpProxy)
            proxy.setHostName(proxyIp)
            proxy.setPort(proxyPort)
            self.webPage.networkAccessManager().setProxy(proxy)
        elif self.proxyIp!=None:
            proxy=QNetworkProxy()
            proxy.setType(QNetworkProxy.HttpProxy)
            proxy.setHostName(self.proxyIp)
            proxy.setPort(self.proxyPort)
            self.webPage.networkAccessManager().setProxy(proxy)

        req=QNetworkRequest(QUrl(url))
        if otherHeaderDict!=None:
            for headerName,headerValue in otherHeaderDict.items():
                req.setRawHeader(QByteArray(headerName),QByteArray(headerValue))
        #print str(QNetworkAccessManager.GetOperation)
        #print str(QNetworkAccessManager.PostOperation)
        self.otherHeaderDict=otherHeaderDict

        if method=='GET':
            self.webView.load(req,QNetworkAccessManager.GetOperation)
        else:
            self.webView.load(req,QNetworkAccessManager.PostOperation,QByteArray(body))

        while self._loadStatus!='end':
            if self._loadStatus=="error":
                break
            if time.time()-alarm >=1:
                break
            self.waitLoad()
        self._loadStatus="init"
        return True

    def getUrl(self):
        '''
        鑾峰彇褰撳墠Frame鐨刄RL
        '''
        return self.webFrame.url()

    def getElements(self,selector):
        return self.webFrame.findAllElements(selector).toList()

    def getPosition(self, selector, real=False,offsetx=0, offsety=0):
        """Get the position QPoint(x,y) of a css selector.
        @param selector: The css Selector to query against
        """
        #jscode = "off = %s('%s').offset(); off.left+','+off.top" % (self.jslib, selector)
        #self._replies = 0
        try:
            item = self.webFrame.findFirstElement(selector)
            geo = item.geometry()
            twhere = geo.topLeft()
            twhere = QPoint(int(twhere.x()),
                            int(twhere.y()))
            #print str(twhere.x())+","+str(twhere.y())
            if real==False:
                return twhere
            where = self.webView.mapToGlobal(twhere)
            if where == twhere:
                where = self.webView.mapToGlobal(where)
        except:
            return where
        return where

    #view action
    def foucs(self,element):
        pass

    #Event Action
    def keyDown(self,key,timeOut=0.1,modifer=Qt.NoModifier):
        eventp = QKeyEvent(QEvent.KeyPress, key, modifer)
        self.application.sendEvent(self.webView, eventp)
        self.waitLoop(timeOut)
        pass

    def keyUp(self,key,timeOut=0.1,modifer=Qt.NoModifier):
        eventp = QKeyEvent(QEvent. KeyRelease, key, modifer)
        self.application.sendEvent(self.webView, eventp)
        self.waitLoop(timeOut)
        pass

    def keyClick(self,key,timeOut=0.1,downToUpTime=0.05):
        self.keyDown(key,timeOut=0)
        self.waitLoop(downToUpTime)
        self.keyUp(key,timeOut=0)
        self.waitLoop(timeOut)
        pass

    def inputText(self,text,timeOut=0.1):
        inputEvent = QKeyEvent(QEvent.KeyPress, Qt.Key_A, Qt.NoModifier, QString(text))
        self.application.sendEvent(self.webView, inputEvent)
        self.waitLoop(timeOut)
        pass

    def mouseMoveToPoint(self, where, timeOut=1, real=False,
                  offsetx=0, offsety=0,
                  adapt_size=False, pdb=False):
        where = QPoint(int(where.x())+offsetx,
                       int(where.y())+offsety)
        eventp = QMouseEvent(5, where,0, Qt.MouseButtons(0), Qt.NoModifier)
        self.webView.setMouseTracking(True)
        self.webView.mouseMoveEvent(eventp)
        self.waitLoop(timeOut)
        return where

        '''
        self.webView.grabMouse()
        #self._events_loop(timeout)
        #cursorw = self.application.desktop().cursor()
        cursorw = QCursor()
        cursorw.setPos(where)
        self.webView.releaseMouse()
        self.waitLoop(timeout)
        return cursorw
        '''

    def mouseMoveToElement(self,selector,offsetx=0,offsety=0,timeOut=0):
        self.mouseMoveToPoint(
            self.getPosition(
                selector,
                offsetx=offsetx, offsety=offsety),
            timeOut=0,
            real=False)
        self.waitLoop(timeOut)

    def mouseDown(self,where,timeOut=0.1):
        eventp = QMouseEvent(2, where,1, Qt.MouseButtons(1), Qt.NoModifier)
        self.webView.mousePressEvent(eventp)
        self.waitLoop(timeOut)
        pass

    def mouseUp(self,where,timeOut=0.1):
        eventp = QMouseEvent(3, where,1, Qt.MouseButtons(0), Qt.NoModifier)
        self.webView.mouseReleaseEvent(eventp)
        self.waitLoop(timeOut)
        pass

    def mouseClickByPoint(self,where,timeOut=0.2,downToUpTime=0):
        self.mouseDown(where)
        self.waitLoop(downToUpTime)
        self.mouseUp(where)
        self.waitLoop(timeOut)
        pass

    def mouseClickByElement(self,selector,timeOut=0.2,downToUpTime=0):
        point=self.getPosition(selector)
        self.mouseClickByPoint(point,0,downToUpTime)
        self.waitLoop(timeOut)
        pass

    def mouseDoubleClickByPoint(self,where,timeOut=0.1,downToUpTime1=0,downToUpTime2=0,doubleTime=0.05):
        self.mouseClickByPoint(where,0,downToUpTime1)
        self.waitLoop(doubleTime)
        eventp = QMouseEvent(4, where,1, Qt.MouseButtons(1), Qt.NoModifier)
        self.webView.mousePressEvent(eventp)
        self.waitLoop(downToUpTime2)
        self.mouseUp(where,0)
        self.waitLoop(timeOut)
        pass

    def mouseDoubleClickByElement(self,selector,timeOut=0.1,downToUpTime1=0,downToUpTime2=0,doubleTime=0.05):
        point=self.getPosition(selector)
        self.mouseDoubleClickByPoint(point,timeOut=0,downToUpTime1=downToUpTime1,downToUpTime2=downToUpTime2,doubleTime=doubleTime)
        self.waitLoop(timeOut)
        pass


    def _updateCookie(self,url,rootHost,path,cookieDict):
        cookieJar=self.webPage.networkAccessManager().cookieJar()
        cookies=cookieJar.cookiesForUrl(QUrl(url))
        flag=False
        for cookieName,cookieValue in cookieDict.items():
            for i in xrange(len(cookies)):
                if cookies[i].name().data()==cookieName:
                    cookies[i].setValue(cookieValue)
                    flag=True
            if flag==False:
                qtCookie=QNetworkCookie(cookieName,cookieValue)
                qtCookie.setDomain(rootHost)
                qtCookie.setPath(path)
                qtCookie.setSecure(False)
                cookies.append(qtCookie)

        self.webPage.networkAccessManager().cookieJar().setCookiesFromUrl(cookies,QUrl(url))

    def _alertHook(self,frame,message):
        #print "alert hook"
        if self.javascriptAlertHook!=None:
            self.javascriptAlertHook.report(self.url,frame,message)

    def _onLoadStarted(self):
        self._loadStatus='start'

    def _onLoadFinished(self,status):
        if status:
            self._loadStatus='end'

    def _debug(self,str):
        #print str
        pass

    def _mustDebug(str):
        #print str
        pass

    def _onManagerSslErrors(self, reply, errors):
        url = unicode(toString(reply.url()))
        #if self.ignore_ssl_errors:
        #   self._debug(WARNING, "SSL certificate error ignored: %s" % url)
        if self.isIgnoreSslError==True:
            reply.ignoreSslErrors()
        #else:
        #    self._debug(WARNING, "SSL certificate error: %s" % url)



    def _onReply(self, reply):
        '''
        self._replies += 1
        self._reply_url = unicode(toString(reply.url()))
        self._reply_status = not bool(reply.error())
        self.cookies = merge_cookies(
            self.cookies,
            self.manager.cookieJar().allCookies())
        '''
        #print 'jkl'
        self._reply_url = unicode(toString(reply.url()))
        self.reply_url=toString(reply.url())
        self._reply_status = not bool(reply.error())
        self.responseNum+=1
        #print str(reply.readAll().length())
        try:
            http_status = "%s" % toString(
                reply.attribute(QNetworkRequest.HttpStatusCodeAttribute))
            http_status_m = "%s" % toString(
                reply.attribute(QNetworkRequest.HttpReasonPhraseAttribute))
        except:
            http_status_m, http_status = "", ""
 
 
        if reply.error():
            self._loadStatus="error"
            self._debug( "Reply error: %s/%s %s - %d (%s)" %
                (http_status, http_status_m,
                 self._reply_url, reply.error(), reply.errorString()))
            self.errorCode = reply.error()
            self.errorMessage = reply.errorString()
        else:
            self._debug("Reply: %s/%s - %s" % (http_status, http_status_m, self._reply_url))
        for header in reply.rawHeaderList():
            self._debug( "  %s: %s" % (header, reply.rawHeader(header)))

  


